package com.dragon.modules.yuegou.service.impl.coupon;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragon.common.exception.DragonException;
import com.dragon.common.web.PageRequest;
import com.dragon.modules.yuegou.entity.coupon.ParkApplyEntity;
import com.dragon.modules.yuegou.entity.merchant.MerchantEntity;
import com.dragon.modules.yuegou.entity.merchant.MerchantQrcodeEntity;
import com.dragon.modules.yuegou.entity.merchant.UserEntity;
import com.dragon.modules.yuegou.entity.product.SkuEntity;
import com.dragon.modules.yuegou.entity.product.SpuEntity;
import com.dragon.modules.yuegou.enums.code.BusinessCode;
import com.dragon.modules.yuegou.enums.code.CouponCode;
import com.dragon.modules.yuegou.enums.code.LimitSalesCode;
import com.dragon.modules.yuegou.enums.coupon.ParkApplyCheckRecordStatus;
import com.dragon.modules.yuegou.enums.coupon.ParkApplyStatus;
import com.dragon.modules.yuegou.enums.coupon.ParkApplyType;
import com.dragon.modules.yuegou.enums.merchant.MerchantQrcodeStatus;
import com.dragon.modules.yuegou.enums.merchant.MerchantQrcodeType;
import com.dragon.modules.yuegou.enums.order.OrderType;
import com.dragon.modules.yuegou.enums.product.StockChangeType;
import com.dragon.modules.yuegou.excel.coupon.ApplyWorkbook;
import com.dragon.modules.yuegou.mapper.coupon.ParkApplyMapper;
import com.dragon.modules.yuegou.model.coupon.MerchantCoupon;
import com.dragon.modules.yuegou.model.coupon.ParkApply;
import com.dragon.modules.yuegou.model.coupon.ParkApplyCheckRecord;
import com.dragon.modules.yuegou.model.merchant.Merchant;
import com.dragon.modules.yuegou.model.merchant.User;
import com.dragon.modules.yuegou.model.order.Order;
import com.dragon.modules.yuegou.model.system.Document;
import com.dragon.modules.yuegou.query.coupon.ApplyCouponQuery;
import com.dragon.modules.yuegou.query.coupon.ParkApplyQuery;
import com.dragon.modules.yuegou.query.merchant.UserQuery;
import com.dragon.modules.yuegou.service.coupon.MerchantCouponService;
import com.dragon.modules.yuegou.service.coupon.ParkApplyCheckRecordService;
import com.dragon.modules.yuegou.service.coupon.ParkApplyService;
import com.dragon.modules.yuegou.service.merchant.MerchantQrcodeService;
import com.dragon.modules.yuegou.service.merchant.MerchantService;
import com.dragon.modules.yuegou.service.order.OrderService;
import com.dragon.modules.yuegou.service.product.SkuService;
import com.dragon.modules.yuegou.service.product.SpuService;
import com.dragon.modules.yuegou.service.product.StockService;
import com.dragon.modules.yuegou.service.system.DocumentService;
import com.dragon.modules.yuegou.service.system.UserService;
import com.dragon.modules.yuegou.utils.DateUtil;
import com.dragon.modules.yuegou.utils.Functions;
import com.dragon.modules.yuegou.web.Check;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
 * 停车券券申请表 服务实现
 *
 * @author pbuilder generated
 * @date 2019-05-30 09:30:12
 * @version 2.0
 */
@Service("coupParkApplyService")
public class ParkApplyServiceImpl extends ServiceImpl<ParkApplyMapper, ParkApplyEntity>
		implements ParkApplyService {

	@Autowired
	private OrderService orderService;

	@Autowired
	private MerchantService merchantService;

	@Autowired
	private MerchantCouponService merchantCouponService;

	@Autowired
	private SkuService skuService;

	@Autowired
	private MerchantQrcodeService merchantQrcodeService;

	@Autowired
	private SpuService spuService;

	@Autowired
	private DocumentService documentService;

	@Autowired
	private ParkApplyCheckRecordService parkApplyCheckRecordService;

	@Autowired
	private com.dragon.modules.yuegou.service.merchant.UserService userService;

	@Autowired
	private UserService sysUserService;

	@Autowired
	private StockService stockService;

	@Override
	public IPage<ParkApply> appylist(PageRequest page, ParkApplyQuery query) {
		Check.notNull(query.getBusdId(), BusinessCode.BUSDID_NOTNULL.getMessage());
		Check.notNull(query.getMerchantId(), "商户ID不能为空");
		if (ParkApplyStatus.READY == query.getStatus()) {
			List<ParkApplyStatus> statusList = new ArrayList<>();
			statusList.add(ParkApplyStatus.READY);
			statusList.add(ParkApplyStatus.UNPASS);
			query.setStatus(null);
			query.status().in(statusList);
		} else if (ParkApplyStatus.PASS == query.getStatus()) {
			List<ParkApplyStatus> statusList = new ArrayList<>();
			statusList.add(ParkApplyStatus.PASS);
			statusList.add(ParkApplyStatus.PREPAID);
			query.setStatus(null);
			query.status().in(statusList);
		} else if (ParkApplyStatus.INVALID == query.getStatus()) {
			query.status().eq(ParkApplyStatus.INVALID);
		}
		query.setType(ParkApplyType.PARK);
		QueryWrapper<ParkApplyEntity> wrapper = query.toQueryWrapper();
		wrapper.orderByDesc(ParkApplyEntity.COL_APPLY_TIME);
		IPage<ParkApplyEntity> entityIPage = new Page<>(page.getPage(),page.getSize(),page.getCount());
		IPage<ParkApplyEntity> iPage = baseMapper.selectPage(entityIPage, wrapper);

		IPage<ParkApply> applyIPage = iPage.convert(ParkApply::new);
		applyIPage.getRecords().stream().forEach(parkApply -> {
			// 查询停车劵模板信息
			SkuEntity sku = skuService.getById(parkApply.getSkuId());
			parkApply.setTitle(sku.getTitle());
			parkApply.setPrice(sku.getDiscountPrice());
		});
		return applyIPage;
	}

	@Override
	public IPage<ParkApply> searchApply(PageRequest page, ApplyCouponQuery query) {
		Page<ParkApplyEntity> entityIPage = new Page<>(page.getPage(),page.getSize(),page.getCount());
		return baseMapper.searchApply(entityIPage, query);
	}

	@Override
	public Document exportApply(ApplyCouponQuery query) {
		List<ParkApply> list = baseMapper.searchApply(query);
		Functions.attachBatch(list, ParkApply::getCheckBy, sysUserService::getByIds,
				(apply, user) -> apply.setCheckName(user.getUsername()));
		ApplyWorkbook applyWorkbook = new ApplyWorkbook();
		List<ApplyWorkbook.ApplyRow> applyRows = new ArrayList<>();
		if (list != null && list.size() > 0) {
			for (ParkApply apply : list) {
				ApplyWorkbook.ApplyRow applyRow = new ApplyWorkbook.ApplyRow();
				applyRow.setMerchantName(apply.getMerchantName());
				applyRow.setCreatedTime(apply.getApplyTime());
				applyRow.setTitle(apply.getTitle());
				applyRow.setEffectTime(apply.getCheckBeginTime() + "-" + apply.getCheckEndTime());
				applyRow.setBuyNum(apply.getBuyNum());
				applyRow.setCheckNum(apply.getCheckNum());
				applyRow.setBuyPrice(apply.getCheckPrice());
				applyRow.setTotalPrice(apply.getPayCash());

				applyRow.setCheckBy(apply.getCheckName());
				applyRows.add(applyRow);
			}
		}
		applyWorkbook.setApply(applyRows);
		return documentService.generateExcel("停车券审核表.xlsx", applyWorkbook);
	}

	@Override
	public ParkApply getApply(String id) {
		Check.notNull(id, "id is required");
		ParkApplyEntity entity = getById(id);
		ParkApply parkApply = new ParkApply(entity);
		SkuEntity sku  = skuService.getById(parkApply.getSkuId());
		parkApply.setPrice(sku.getDiscountPrice());
		parkApply.setTitle(sku.getTitle());
		parkApply.setSpuId(sku.getSpuId());
		return parkApply;
	}

	@Override
	@Transactional
	public void checkCoupon(ParkApply parkApply) {
		// 数据校验
		checkData(parkApply);
		// 审核申请
		checkApplyAndModify(parkApply);
		// 创建审核记录
		createCheckRecord(parkApply);
	}

	private void checkData(ParkApply parkApply) {
		Check.notEmpty(parkApply.getId().toString(), "id不能为空");
		Check.notNull(parkApply.getStatus(), "状态不能为空");
		if (parkApply.getStatus() == ParkApplyStatus.UNPASS && StringUtils.isEmpty(parkApply.getCheckRs())) {
			throw new DragonException(CouponCode.CHECK_RD_IS_NOT_EMPTY);
		}
		if (parkApply.getStatus() == ParkApplyStatus.PASS) {
			if (parkApply.getCheckPrice().compareTo(BigDecimal.ZERO) < 1) {
				throw new DragonException(CouponCode.PRICE_ERROR);
			}
			Check.notNull(parkApply.getCheckNum(), "审核数量不能为空");
			Check.digits(parkApply.getCheckNum(), 5, 0, "审核数量必须是正整数");
			Check.positive(parkApply.getCheckNum(), "审核数量必须是正数");
			Check.notNull(parkApply.getCheckPrice(), "审核单价不能为空");
			Check.digits(parkApply.getCheckPrice(), 10, 2, "审核单价格式不正确");
			Check.notNull(parkApply.getPayCash(), "审核总金额不能为空");
			Check.digits(parkApply.getPayCash(), 10, 2, "审核总金额格式不正确");
			Check.notNull(parkApply.getCheckBeginTime(), "审核开始有效期");
			Check.notNull(parkApply.getCheckEndTime(), "审核结束有效期");
			parkApply.setCheckEndTime(DateUtil.getFormaterEndTime(parkApply.getCheckEndTime()));
		}
	}

	private void checkApplyAndModify(ParkApply parkApply) {
		ParkApplyQuery query = new ParkApplyQuery();
		query.setStatus(ParkApplyStatus.UNCHECK);
		query.setId(parkApply.getId());
		parkApply.setCheckBy("");
		parkApply.setCheckTime(LocalDateTime.now());
		if (baseMapper.update(parkApply, query.toQueryWrapper()) < 1) {
			throw new DragonException(CouponCode.STATUS_WRONG);
		}
	}

	@Override
	@Transactional
	public void giftCoupon(ParkApply parkApply) {
		parkApply.setStatus(ParkApplyStatus.PAYED);
		parkApply.setCheckRs("系统赠送");
		parkApply.setPayCash(BigDecimal.ZERO);
		// 审核申请记录
		checkApplyAndModify(parkApply);
		parkApply.setStatus(ParkApplyStatus.PASS);
		// 创建审核记录
		createCheckRecord(parkApply);
		// 扣除停车券库存
		stockService.changeStock(parkApply.getSkuId(), 0 - parkApply.getCheckNum(), StockChangeType.EDIT);
		// 给商户发放停车券
		grantParkCoupon(parkApply);
	}

	public void grantParkCoupon(ParkApply parkApply) {
		MerchantCoupon merchantCoupon = new MerchantCoupon();
		merchantCoupon.setId(IdWorker.getIdStr());
		merchantCoupon.setMerchantId(parkApply.getMerchantId());
		merchantCoupon.setParkApplyId(parkApply.getId());
		merchantCoupon.setCouponTemplateId(skuService.getTemplateId(parkApply.getSkuId()));
		merchantCoupon.setTotal(parkApply.getCheckNum());
		merchantCoupon.setGranted(0);
		merchantCoupon.setStock(parkApply.getCheckNum());
		merchantCoupon.setVersion(0);
		merchantCoupon.setCreatedBy(parkApply.getApplyBy());
		merchantCouponService.save(merchantCoupon);

		List<MerchantQrcodeEntity> qrcodeList = new ArrayList<>();
		MerchantQrcodeType qrcodeType = ParkApplyType.DISCOUNT.equals(parkApply.getType()) ? MerchantQrcodeType.COUPON : MerchantQrcodeType.PARK;
		for (int i = 0; i < parkApply.getCheckNum(); i++) {
			MerchantQrcodeEntity qrcode = new MerchantQrcodeEntity();
			qrcode.setMerchantId(merchantCoupon.getMerchantId());
			qrcode.setMerchantCouponId(merchantCoupon.getId());
			qrcode.setStatus(MerchantQrcodeStatus.READY);
			qrcode.setType(qrcodeType);
			qrcodeList.add(qrcode);
		}
		merchantQrcodeService.saveBatch(qrcodeList);
	}
	private void createCheckRecord(ParkApply parkApply) {
		// 插入审核记录
		ParkApplyCheckRecord parkApplyCheckRecord = new ParkApplyCheckRecord();
		parkApplyCheckRecord.setParkApplyId(parkApply.getId());
		parkApplyCheckRecord.setCheckReason(parkApply.getCheckRs());
		parkApplyCheckRecord.setCheckedBy(parkApply.getCheckBy());
		parkApplyCheckRecord.setCheckTime(parkApply.getCheckTime());
		parkApplyCheckRecord.setMerchantId(parkApply.getMerchantId());
		if (parkApply.getStatus() == ParkApplyStatus.PASS) {
			parkApplyCheckRecord.setStatus(ParkApplyCheckRecordStatus.PASS);
		} else {
			parkApplyCheckRecord.setStatus(ParkApplyCheckRecordStatus.UNPASS);
		}
		parkApplyCheckRecordService.save(parkApplyCheckRecord);
	}

	@Override
	public void cancel(String id) {
		ParkApplyEntity apply = this.getById(id);
		apply.setStatus(ParkApplyStatus.READY);
		baseMapper.updateById(apply);
	}

	private void checkExpred(ParkApply apply) {
		LocalDateTime now = LocalDateTime.now();
		if (apply.getEndTime().isBefore(now)) {
			if (!apply.getStatus().equals(ParkApplyStatus.INVALID)) {
				apply.setStatus(ParkApplyStatus.INVALID);
				baseMapper.updateById(apply);
			}
			throw new DragonException(CouponCode.MERCHANT_COUPON_APPLY_EXPRIED);
		}
	}

	@Override
	public Order order(String merchantUserId, String parkApplyId) {
		ParkApply apply = this.getApply(parkApplyId);
		checkExpred(apply);

		User user = userService.getBySysUserId(merchantUserId);
		MerchantEntity merchant = merchantService.getById(user.getMerchantId());

		Order request = new Order();
		request.setMerchantBuyer(new Merchant(merchant));
		request.setMerchantName(merchant.getMerchantName());
		request.setType(OrderType.MERCHANT_COUPON_BUY);
		request.setMerchantId(merchant.getId());
		request.setBusdId(apply.getBusdId());
		request.addItem(apply.getSkuId(), apply.getCheckNum(), apply.getCheckPrice());

		Order order = orderService.placeOrder(request);
		if (null != order.getId()) {
			apply.setStatus(ParkApplyStatus.PREPAID);
			apply.setOrderNo(order.getId());
			baseMapper.updateById(apply);
		}
		return order;
	}

	@Override
	public ParkApply prepaid(String parkApplyId) {
		ParkApply apply = this.getApply(parkApplyId);
		if (checkExpried(apply.getEndTime())) {
			if (!apply.getStatus().equals(ParkApplyStatus.INVALID)) {
				apply.setStatus(ParkApplyStatus.INVALID);
				baseMapper.updateById(apply);
			}
			throw new DragonException(CouponCode.MERCHANT_COUPON_APPLY_EXPRIED);
		}

		checkExpred(apply);

		SpuEntity spu = spuService.getById(apply.getSpuId());
		if (checkExpried(spu.getEndTime())) {
			if (!apply.getStatus().equals(ParkApplyStatus.INVALID)) {
				apply.setStatus(ParkApplyStatus.INVALID);
				baseMapper.updateById(apply);
			}
			throw new DragonException(CouponCode.MERCHANT_COUPON_APPLY_EXPRIED);
		}
		return apply;
	}

	/**
	 * 判断是否过期
	 * 
	 * @param endTime
	 * @return
	 */
	private boolean checkExpried(LocalDateTime endTime) {
		LocalDateTime now = LocalDateTime.now();
		return endTime.isBefore(now);
	}

	@Override
	@Transactional
	public void payCallBack(MerchantCoupon merchantCoupon, String orderNo) {
		Order order = orderService.getOrder(orderNo);

		// 生成商户申请停车券数据
		ParkApplyQuery query = new ParkApplyQuery();
		query.orderNo().eq(orderNo);
		ParkApplyEntity apply = getOne(query.toQueryWrapper());

		if (null != apply) {
			if (null == merchantCoupon.getCreatedBy()) {
				UserQuery userQuery = new UserQuery();
				userQuery.merchantId().eq(apply.getMerchantId());
				UserEntity user = userService.getOne(userQuery.toQueryWrapper());
				if (null != user) {
					merchantCoupon.setCreatedBy(user.getId());
				}
			}
			merchantCoupon.setParkApplyId(apply.getId());
			merchantCouponService.updateById(merchantCoupon);

			List<MerchantQrcodeEntity> qrcodeList = new ArrayList<>();
			for (int i = 0; i < apply.getCheckNum(); i++) {
				MerchantQrcodeEntity qrcode = new MerchantQrcodeEntity();
				qrcode.setMerchantId(merchantCoupon.getMerchantId());
				qrcode.setMerchantCouponId(merchantCoupon.getId());
				qrcode.setStatus(MerchantQrcodeStatus.READY);
				qrcode.setType(MerchantQrcodeType.PARK);
				qrcodeList.add(qrcode);
			}
			merchantQrcodeService.saveBatch(qrcodeList);
			apply.setPayCash(order.getPayableAmount());
			apply.setStatus(ParkApplyStatus.PAYED);
			baseMapper.updateById(apply);

		} else {
			throw new DragonException(CouponCode.MERCHANT_COUPON_APPLY_NOT_FIND);
		}
	}

	@Override
	public String apply(ParkApply parkApply) {
		Check.notNull(parkApply.getSkuId(), "申请购买的类型不能为空");
		Check.notNull(parkApply.getBuyNum(), "申请购买数量不能为空");
		Check.notNull(parkApply.getBeginTime(), "有效开始时间不能为空");
		Check.notNull(parkApply.getEndTime(), "有效结束时间不能为空");

		// 判断spu的有效期
		checkProductTime(parkApply);

		parkApply.setApplyBy("");
		parkApply.setApplyTime(LocalDateTime.now());

		parkApply.setCheckEndTime(DateUtil.getFormaterEndTime(parkApply.getCheckEndTime()));
		parkApply.setEndTime(DateUtil.getFormaterEndTime(parkApply.getEndTime()));
		parkApply.setUseNum(0);
		baseMapper.insert(parkApply);
		return parkApply.getId();
	}

	private void checkProductTime(ParkApply parkApply) {
		SkuEntity sku = skuService.getById(parkApply.getSkuId());
		SpuEntity spu = spuService.getById(sku.getSpuId());
		if (spu.getEndTime() != null && parkApply.getEndTime().isAfter(spu.getEndTime())) {
			throw new DragonException(LimitSalesCode.LIMITSALES_SPU_TIME_OUT);
		}
	}

	@Override
	public void submitCheck(String id) {
		ParkApplyEntity parkApply = getById(id);
		parkApply.setStatus(ParkApplyStatus.UNCHECK);
		baseMapper.updateById(parkApply);
	}

}